package resolver

import (
	"auto-wallpaper/eval"
	"auto-wallpaper/profile"
	"fmt"
	"github.com/Knetic/govaluate"
	"github.com/PuerkitoBio/goquery"
	"github.com/gocolly/colly"
	"net/http"
	"strings"
	"time"
)

var collector = colly.NewCollector()

func createCollector() {
	collector = colly.NewCollector()
	rule := &colly.LimitRule{
		RandomDelay: time.Second,
		Parallelism: 1, //并发数为10
	}
	_ = collector.Limit(rule)
}

// ResolveImg 解析图片
func ResolveImg(imgChan chan string) {
	createCollector()
	go func() {
		ResolverImg(*profile.Steps, imgChan)
		close(imgChan)
	}()
}

// ResolverImg 执行解析获取图片
func ResolverImg(steps []profile.Step, imgChan chan<- string) {

	if len(steps) <= 0 {
		return
	}
	for _, step := range steps {
		if step.DownSleep > 0 {
			time.Sleep(time.Millisecond * time.Duration(step.DownSleep))
		}
		// 获取html
		currUrl := step.CurrUrl
		html, err := getHtml(currUrl)

		// 局部变量
		m := map[string]interface{}{}
		// 设置参数
		setMap(step, m)
		setMapByQuery(html, step, m)
		// 解析图片地址
		resolveImg(step, html, m, imgChan)
		// 解析下一个节点
		err, nextUrl := resolveNextUrl(step, err, html, m)
		// 执行下一个节点
		doNext(step, nextUrl, imgChan)
		if err != nil {
			fmt.Printf("请求失败 : %v", err)
		}
	}

}

//getHtml 获取html
func getHtml(currUrl string) (*goquery.Document, error) {
	configSet := profile.AppConfigSet

	header := http.Header{}
	for k, v := range configSet.Header {
		header.Add(k, v)
	}
	var html *goquery.Document
	collector.OnResponse(func(response *colly.Response) {
		html, _ = goquery.NewDocumentFromReader(strings.NewReader(string(response.Body)))

	})
	var err error
	if len(currUrl) > 0 {
		err := collector.Request("GET", currUrl, nil, nil, header)
		if nil != err {
			fmt.Printf("解析html出错 : %v\n", err)
		}
	}
	return html, err
}

// doNext 执行下一个节点
func doNext(step profile.Step, nextUrl []string, imgChan chan<- string) {
	nextStep := step.Next
	if nil != nextStep && len(nextUrl) > 0 {
		// 递归 解析子节点
		var nextList []profile.Step
		for _, v := range nextUrl {
			next := profile.Step{CurrUrl: v, Img: nextStep.Img, Set: nextStep.Set, SetQuery: nextStep.SetQuery,
				NextUrl: nextStep.NextUrl, Next: nextStep.Next, DownSleep: nextStep.DownSleep}
			nextList = append(nextList, next)
		}
		ResolverImg(nextList, imgChan)

	}
}

//resolveNextUrl 获取下一个节点
func resolveNextUrl(step profile.Step, err error, html *goquery.Document, m map[string]interface{}) (error, []string) {
	var nextUrl []string
	if len(step.NextUrl) > 0 {
		// 遍历获取下一个节点的url
		for _, opera := range step.NextUrl {
			var expression *govaluate.EvaluableExpression
			if len(opera.Eval) > 0 {
				expression, err = eval.NewEval(opera.Eval)
				if err != nil {
					fmt.Println(err)
				}
			}
			if html != nil {
				nodes := html.Find(opera.Query)
				if nil != nodes && len(nodes.Nodes) > 0 {
					for _, v := range nodes.Nodes {
						if nil != expression {
							m[opera.Key] = v
							res, err := expression.Evaluate(m)
							if err != nil {
								fmt.Println(err)
							}
							nextUrl = append(nextUrl, fmt.Sprintf("%v", res))
						}
					}
				}
			}

		}
	}
	return err, nextUrl
}

//resolveImg 解析html获取图片
func resolveImg(step profile.Step, html *goquery.Document, m map[string]interface{}, imgChan chan<- string) {
	img := step.Img
	if nil != &img {
		// 解析图片
		var expression *govaluate.EvaluableExpression
		if len(img.Eval) > 0 {
			expression, _ = eval.NewEval(img.Eval)
		}
		if html != nil && len(img.Query) > 0 {
			nodes := html.Find(img.Query)
			if nil != nodes && len(nodes.Nodes) > 0 {
				for _, v := range nodes.Nodes {
					if nil != expression {
						m[img.Key] = v
						res, _ := expression.Evaluate(m)
						imgChan <- fmt.Sprintf("%v", res)
					} else {
						imgChan <- v.Data
					}
				}
			}
		}

	}
}

// setMapByQuery 设置参数
func setMapByQuery(html *goquery.Document, step profile.Step, m map[string]interface{}) {
	if html != nil && len(step.SetQuery) > 0 {
		// 通过xpath获取局部变量
		for k, query := range step.SetQuery {
			xp := fmt.Sprintf("%v", query)
			nodes := html.Find(xp)
			if nil != nodes && len(nodes.Nodes) > 0 {
				for _, v := range nodes.Nodes {
					m[k] = v.Data

				}
			}
		}
	}
}

// setMap 设置参数
func setMap(step profile.Step, m map[string]interface{}) {
	if len(step.Set) > 0 {
		// 获取配置中的局部变量
		for k, v := range step.Set {
			m[k] = v
		}
	}
}
